package com.Image.aop;

import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author kevin
 * @desc 入口日志切面
 */
public class EntranceLogAdvice implements MethodInterceptor {
	private static Logger logger = LoggerFactory.getLogger(EntranceLogAdvice.class);
	private static ThreadLocal<Long> startTime = new ThreadLocal<Long>();
	private static ThreadLocal<Boolean> isException = new ThreadLocal<Boolean>();

	/* (non-Javadoc)
	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
	 */
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object[] args = invocation.getArguments();
		HttpServletRequest request = null;
		for (Object arg : args) {
			if (HttpServletRequest.class.isAssignableFrom(arg.getClass())) {
				request = (HttpServletRequest)arg;
				break;
			}
		} 
		if (null == request) {
			logger.warn("Controller entrance with no HttpServletRequest paramter. args:{}", Arrays.toString(args));
		}
		
		logRequestStart(request);
		
		Object object = null;
		isException.set(false);
		try {
			object = invocation.proceed();
		}
		catch (Throwable t) {
			logger.error("Uncaught exception! Trace:", t);
			isException.set(true);
		} 
		
		logRequestEnd(request);
		
		return object;
	}
	
	private String getUri(HttpServletRequest request) {
		if (null != request) {
			String queryString = request.getQueryString();
			return request.getRequestURI() + ((null == queryString) ? "" : "?" + queryString);
		}
		return "unknown";
	}

	private String getAddress(HttpServletRequest request) {
		if (null == request) {
			return "unknown";
		}
		
	    String ip = request.getHeader("x-forwarded-for");
	    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
	        ip = request.getHeader("Proxy-Client-IP");
	    }
	    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
	        ip = request.getHeader("WL-Proxy-Client-IP");
	    }
	    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
	        ip = request.getRemoteAddr();
	    }
	    
	    return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
	}
	
	private Integer getUserID(HttpServletRequest request) {
		if (null == request) {
			return -1;
		}
		Object uidObject = request.getSession().getAttribute("userID");
		if (null != uidObject) {
			return (Integer)uidObject;
		}
		return -1;
	}

	/**
	 * 请求入口日志打印
	 * @param request
	 */
	private void logRequestStart(HttpServletRequest request) {
		Long startMillis = System.currentTimeMillis();
		startTime.set(startMillis);
		String reqUri = getUri(request);
		String remoteAddr = getAddress(request);
		Integer uid = getUserID(request);
		logger.info("Start request [{}]. uid:{}, ip:{}, startTime:{}.", new Object[] {reqUri, uid, remoteAddr, startMillis});
	}

	/**
	 * 请求出口日志打印
	 * @param request
	 */
	private void logRequestEnd(HttpServletRequest request) {
		String reqUri = getUri(request);
		String remoteAddr = getAddress(request);
		Long endMillis = System.currentTimeMillis();
		Integer uid = getUserID(request);
		if (!isException.get()) {
			logger.info("End request [{}]. uid:{}, ip:{}, consumed:{}.", 
					new Object[] {reqUri, uid, remoteAddr, endMillis - startTime.get()});
		}
		else {
			logger.error("Exception end request [{}]. uid:{}, ip:{}, consumed:{}.", 
					new Object[] {reqUri, uid, remoteAddr, endMillis - startTime.get()});
		}
	}
}
